/**
  ******************************************************************************
  * @author     Chris
  * @since      2024/7/1 14:14
  *
  * @file       hd_nrf24l01.c
  * @brief      Xxx hardware driver.
  *
  * @note       This file contains the hardware driver for the Xxx.
  *
  * @warning    None.
  ******************************************************************************
  * Change Logs:
  *   Date          Author       Notes
  *   2024/7/1     Chris        the first version
  *
  ******************************************************************************
  */


#include <delay.h>
#include <string.h>
#include "hd_nrf24l01.h"

const uint8_t TX_ADDRESS[TX_ADR_WIDTH] = {0x34, 0x43, 0x10, 0x10, 0x01};
const uint8_t RX_ADDRESS[RX_ADR_WIDTH] = {0x34, 0x43, 0x10, 0x10, 0x01};

#if 0
static uint8_t writeReg(struct NRF24L01 *this, uint8_t reg, uint8_t byte) {
    SPI_start(this->spi, this->csn);

    uint8_t status = SPI_swapByte(this->spi, reg);
    SPI_swapByte(this->spi, byte);

    SPI_stop(this->spi, this->csn);

    return status;
}

static uint8_t readReg(struct NRF24L01 *this, uint8_t reg) {
    SPI_start(this->spi, this->csn);

    SPI_swapByte(this->spi, reg);
    uint8_t regVal = SPI_swapByte(this->spi, 0x00);

    SPI_stop(this->spi, this->csn);

    return regVal;
}
#endif

static uint8_t readBuf(struct NRF24L01 *this, uint8_t reg, uint8_t *buf, uint8_t bytes) {
    SPI_start(this->spi, this->csn);

    uint8_t status = SPI_swapByte(this->spi, reg);
    while (bytes--) {
        *buf++ = SPI_swapByte(this->spi, 0x00);
    }

    SPI_stop(this->spi, this->csn);

    return status;
}

static uint8_t writeBuf(struct NRF24L01 *this, uint8_t reg, uint8_t *buf, uint8_t bytes) {
    SPI_start(this->spi, this->csn);

    uint8_t status = SPI_swapByte(this->spi, reg);
    delay_ms(10);
    while (bytes--) {
        SPI_swapByte(this->spi, *buf++);
    }

    SPI_stop(this->spi, this->csn);

    return status;
}

#if 0
static uint8_t NRF24L01_txPacket(struct NRF24L01 *this, uint8_t *txbuf) {
    uint8_t sta;

    GPIO_reset(this->ce);

    writeBuf(this, WR_TX_PLOAD, txbuf, TX_PLOAD_WIDTH);
    GPIO_set(this->ce);

    while (GPIO_get(this->irq) != 0);         // wait for tx

    sta = readReg(this, STATUS);
    writeReg(this, WRITE_REG_CMD + STATUS, sta);
    if (sta & MAX_TX) {
        writeReg(this, FLUSH_TX, 0xff);
        return MAX_TX;
    }

    if (sta & TX_OK) return TX_OK;
    return 0xff;
}

static uint8_t NRF24L01_rxPacket(struct NRF24L01 *this, uint8_t *rxbuf) {
    uint8_t sta;

    sta = readReg(this, STATUS);
    writeReg(this, WRITE_REG_CMD + STATUS, sta);
    if (sta & RX_OK) {
        readBuf(this, RD_RX_PLOAD, rxbuf, RX_PLOAD_WIDTH);
        writeReg(this, FLUSH_RX, 0xff);
        return 0;
    }

    return 1;
}

static void NRF24L01_rxMode(struct NRF24L01 *this) {
    GPIO_reset(this->ce);

    writeBuf(this, WRITE_REG_CMD + RX_ADDR_P0, (uint8_t *) RX_ADDRESS, RX_ADR_WIDTH);
    writeReg(this, WRITE_REG_CMD + EN_AA, 0x01);
    writeReg(this, WRITE_REG_CMD + EN_RXADDR, 0x01);
    writeReg(this, WRITE_REG_CMD + RF_CH, 40);
    writeReg(this, WRITE_REG_CMD + RX_PW_P0, RX_PLOAD_WIDTH);
    writeReg(this, WRITE_REG_CMD + RF_SETUP, 0x0f);
    writeReg(this, WRITE_REG_CMD + CONFIG, 0x0f);

    GPIO_set(this->ce);
}

static void NRF24L01_txMode(struct NRF24L01 *this) {
    GPIO_reset(this->ce);

    writeBuf(this, WRITE_REG_CMD + TX_ADDR, (uint8_t *) TX_ADDRESS, TX_ADR_WIDTH);
    writeBuf(this, WRITE_REG_CMD + RX_ADDR_P0, (uint8_t *) RX_ADDRESS, RX_ADR_WIDTH);
    writeReg(this, WRITE_REG_CMD + EN_AA, 0x01);
    writeReg(this, WRITE_REG_CMD + EN_RXADDR, 0x01);
    writeReg(this, WRITE_REG_CMD + SETUP_RETR, 0x1a);
    writeReg(this, WRITE_REG_CMD + RF_CH, 40);
    writeReg(this, WRITE_REG_CMD + RF_SETUP, 0x0f);
    writeReg(this, WRITE_REG_CMD + CONFIG, 0x0e);

    GPIO_set(this->ce);
}
#endif

static void NRF24L01_init(struct NRF24L01 *this) {
    GPIO_init(this->ce);
    GPIO_init(this->irq);

    GPIO_reset(this->ce);              // chip enable
    SPI_stop(this->spi, this->csn);  // Chip select disable
}

static uint8_t NRF24L01_check(struct NRF24L01 *this) {
    uint8_t buf[5] = {0XA5, 0XA5, 0XA5, 0XA5, 0XA5};

    writeBuf(this, WRITE_REG_CMD + TX_ADDR, buf, 5);
    uint8_t i;
    for (i = 0; i < 5; ++i) buf[i] = 0x5A;

    readBuf(this, TX_ADDR, buf, 5);

    for (i = 0; i < 5; i++) if (buf[i] != 0XA5) break;

    return i != 5;
}

static struct NRF24L01 new(  SPI *spi,   GPIO *csn,   GPIO *ce,   GPIO *irq) {
    return (struct NRF24L01) {
            .spi = spi,
            .csn = csn,
            .ce = ce,
            .irq = irq,

            .init = &NRF24L01_init,
            .check = &NRF24L01_check,
    };
}

const struct NRF24L01Class NRF24L01 = {.new = &new};

